package com.ayu.shortlink.admin.idempotent;

import com.alibaba.fastjson2.JSON;
import com.ayu.shortlink.admin.common.convention.exception.ClientException;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.util.DigestUtils;

/**
 * AOP实现幂等性
 */
@Aspect
@RequiredArgsConstructor
public class NoRepeatSubmitAspect {
    private final RedissonClient redissonClient;
    /**
     * 使用环绕增强进行
     */
    @Around("@annotation(noRepeatSubmit)")
    public Object handle(ProceedingJoinPoint proceedingJoinPoint, NoRepeatSubmit noRepeatSubmit) throws Throwable {
        //获取标识
        String mark = noRepeatSubmit.Mark();

        String NoRepeatSubmitRedisLockKey = String.format("No-Repeat-Submit:Path:%s:UserId:%s:Md5:%s", mark, getCurrentUserId(), calcArgsMd5(proceedingJoinPoint));
        RLock lock = redissonClient.getLock(NoRepeatSubmitRedisLockKey);
        if(!lock.tryLock()){
            throw new ClientException(noRepeatSubmit.message());
        }
        //储存执行结果
        Object result;
        try {
            result = proceedingJoinPoint.proceed();
        }finally {
            lock.unlock();
        }
        return result;
    }

    /**
     * 返回当前线程的用户 ID
     */
    private String getCurrentUserId(){
        return "2131231";
    }

    /**
     * 计算参数的 MD5 值
     */
    private String calcArgsMd5(ProceedingJoinPoint proceedingJoinPoint){
        return DigestUtils.md5DigestAsHex(JSON.toJSONBytes(proceedingJoinPoint.getArgs()));
    }
}
